#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "main.h"

void printLine(char *string, int *index, int rowHeaderWidth, int columnWidth);
void printHeaderCell(char *string, int *index, int m, int columnWidth);
void printPlaneCell(char *string, int *index, int point, int columnWidth);

/*
 * Vypíše plán s body (fixními i umístěnými podle zadaného stavu)
 */
void printPlane(void) {

	/* index stringu */
	int index = 0;
	int i, j, l, point;
	int mOrder = getOrderOfMagnitude(m - 1);
	int kOrder = getOrderOfMagnitude(k - 1);
	int fOrder = getOrderOfMagnitude(f - 1);
	int columnWidth = maxValue(mOrder, fOrder + 2) + 1;
	int rowHeaderWidth = kOrder + 1;

	/*
	 * Alokace přesně potřebného místa:
	 * 2k+2 --> k řádků + k mezilinek + první řádek s čísly + poslední linka,
	 * rowHeaderWidth --> šířka buňky v prvním sloupci (s čísly),
	 * columnWidth*m --> šířka buňky krát počet sloupců,
	 * + 2 --> závěrečné '|' a konec řádku,
	 * + 1 --> NULL na konec (konec řetězce).
	 */
	char *string = (char *) malloc((2 * k + 2) * (rowHeaderWidth + columnWidth * m + 2) + 1);
	if(string == NULL){
		fprintf(stderr, "Out of memory during plane printout!");
		return;
	}

	/* výpis prvního řádku - čísla */
	for(i = 0; i < rowHeaderWidth; i++){
		index += sprintf(string + index, " ");
	}
	for(i = 0; i < k; i++){
		printHeaderCell(string, &index, i, columnWidth);
	}
	index += sprintf(string + index, "|\n");

	/* výpis řádků plánu */
	for(i = 0; i < m; i++){
		/* každý rádek má grafickou linku */
		printLine(string, &index, rowHeaderWidth, columnWidth);
		/* výpis headeru - čísla řádku */
		for(j = 0; j < rowHeaderWidth - getOrderOfMagnitude(i) - 1; j++){
			index += sprintf(string + index, " ");
		}
		index += sprintf(string + index, "%d", i);
		index += sprintf(string + index, " ");

		/* výpis buněk s daty */
		for(j = 0; j < k; j++){
			point = -2;
			/* hledáme, jestli není na zadaných souřadnicích bod */
			for(l = 0; l < f; l++){
				if(fixedPoints[l].x == i && fixedPoints[l].y == j){
					point = l;
					break;
				}
			}
			for(l = 0; l < (b - f); l++){
				if(variablePoints[l].x == i && variablePoints[l].y == j){
					/* -1 => zapíšeme hvězdičku */
					point = -1;
					break;
				}
			}
			/* zapíšeme buňku */
			if(point >= -1){
				printPlaneCell(string, &index, point, columnWidth);
			}
			else{
				index += sprintf(string + index, "|");
				for(l = 0; l < columnWidth - 1; l++){
					index += sprintf(string + index, " ");
				}
			}
		}
		index += sprintf(string + index, "|\n");
	}
	/* poslední grafická linky */
	printLine(string, &index, rowHeaderWidth, columnWidth);
	string[index] = '\0';

	printf(string);
	free(string);
}

/*
 * Vypíše grafickou linku - rámeček tabulky.
 */
void printLine(char *string, int *index, int rowHeaderWidth, int columnWidth) {
	int i, j;
	for(i = 0; i < rowHeaderWidth; i++){
		*index += sprintf(string + *index, " ");
	}
	for(i = 0; i < k; i++){
		*index += sprintf(string + *index, "+");
		for(j = 0; j < columnWidth - 1; j++){
			*index += sprintf(string + *index, "-");
		}
	}
	*index += sprintf(string + *index, "+\n");
}

/*
 * Vypíše buňku do záhlaví tabulky.
 */
void printHeaderCell(char *string, int *index, int m, int columnWidth) {
	int freeSpace = (columnWidth - 1 - getOrderOfMagnitude(m));
	int freeSpaceLeft = freeSpace / 2;
	int freeSpaceRight = freeSpace / 2;
	int i;

	*index += sprintf(string + *index, "|");

	if(freeSpace % 2 == 1){
		freeSpaceLeft++;
	}
	for(i = 0; i < freeSpaceLeft; i++){
		*index += sprintf(string + *index, " ");
	}
	*index += sprintf(string + *index, "%d", m);
	for(i = 0; i < freeSpaceRight; i++){
		*index += sprintf(string + *index, " ");
	}
}

/*
 * Vypíše buňku tabulky.
 */
void printPlaneCell(char *string, int *index, int point, int columnWidth) {
	int freeSpace = (columnWidth - 1 - getOrderOfMagnitude(point) - 2);
	int freeSpaceLeft = freeSpace / 2;
	int freeSpaceRight = freeSpace / 2;
	int i;

	*index += sprintf(string + *index, "|");
	if(freeSpace % 2 == 1){
		freeSpaceLeft++;
	}
	for(i = 0; i < freeSpaceLeft; i++){
		*index += sprintf(string + *index, " ");
	}
	if(point >= 0){
		*index += sprintf(string + *index, "(%d)", point);
	}
	else{
		*index += sprintf(string + *index, "(*)");
	}
	for(i = 0; i < freeSpaceRight; i++){
		*index += sprintf(string + *index, " ");
	}
}
